
#include "BondType.h"

#include <fstream>

#include "BondContainer.h"
#include "BondDict.h"

/////////////////////////////////////////////////////
// class CBondType
/////////////////////////////////////////////////////

CBondType::CBondType() : m_Code(""), m_Name_C(""), m_Name_E("") {}

CBondType::CBondType(const char* sCode, const char* sName, const char* sNameEn)
    : m_Code(sCode), m_Name_C(sName), m_Name_E(sNameEn) {}

CBondType::~CBondType() { Clear(); }

void CBondType::Clear() {
  m_Code = "";
  m_Name_C = "";
  m_Name_E = "";
  m_list.clear();
}

bool CBondType::operator==(const CBondType& one) {
  if (m_Code == one.m_Code) return true;
  return false;
}

int CBondType::GetSize() { return m_list.size(); }

void CBondType::AddSubType(CBondType& subType) { m_list.push_back(subType); }

std::vector<CBondType>* CBondType::GetBondSubTypeList() { return &m_list; }

CBondType* CBondType::GetBondSubType(const char* szSubBondCode) {
  if (szSubBondCode == NULL) return NULL;
  CBondType stTemp;
  stTemp.m_Code = szSubBondCode;
  vector<CBondType>::iterator itor = find(m_list.begin(), m_list.end(), stTemp);
  if (itor == m_list.end()) return NULL;

  if (itor != m_list.end()) return &(*itor);
  return NULL;
}
/////////////////////////////////////////////////////
// class CBondTypeList
/////////////////////////////////////////////////////

#define _add_bondtype(strtype)                    \
  {                                               \
    dict.GetBondDict("Bond_Type", strtype, unit); \
    type.m_Code = strtype;                        \
    type.m_Name_C = unit.selective_content;       \
    type.m_Name_E = unit.selective_content_en;    \
  }

#define _add_bondsubtype(strtype)                    \
  {                                                  \
    dict.GetBondDict("Bond_Subtype", strtype, unit); \
    sub.m_Code = strtype;                            \
    sub.m_Name_C = unit.selective_content;           \
    sub.m_Name_E = unit.selective_content_en;        \
    type.AddSubType(sub);                            \
  }

CBondTypeList& CBondTypeList::instance() {
  static CBondTypeList s_bondtype;
  return s_bondtype;
}

CBondTypeList::CBondTypeList() {
  CBondType type, sub;
  BondDict unit;
  CBondDict& dict = CBondDict::instance();

  // 国债
  _add_bondtype("GOV");
  _add_bondsubtype("BGB");
  m_list.push_back(type);
  type.Clear();

  // 央票
  _add_bondtype("CBB");
  _add_bondsubtype("SCB");
  m_list.push_back(type);
  type.Clear();

  // 地方债
  type.m_Code = "Local";
  type.m_Name_C = QString("地方债").toLocal8Bit().data();
  type.m_Name_E = "Municipal Bond";
  _add_bondsubtype("LLB");
  _add_bondsubtype("TLB");
  m_list.push_back(type);
  type.Clear();

  // 金融债
  _add_bondtype("FIN");
  _add_bondsubtype("PBB");
  m_list.push_back(type);
  type.Clear();

  // 短融
  _add_bondtype("CPB");
  _add_bondsubtype("CCP");
  _add_bondsubtype("CSP");
  _add_bondsubtype("LCP");
  _add_bondsubtype("LSP");
  m_list.push_back(type);
  type.Clear();

  // 中票
  _add_bondtype("MTN");
  _add_bondsubtype("CMN");
  _add_bondsubtype("LMN");
  m_list.push_back(type);
  type.Clear();

  // 企业债
  _add_bondtype("EPB");
  _add_bondsubtype("CEB");
  _add_bondsubtype("LEB");
  m_list.push_back(type);
  type.Clear();

  // 公司债
  _add_bondtype("COR");
  _add_bondsubtype("COP");
  {
    CBondType* pSub = type.GetBondSubType("COP");
    if (pSub != NULL) {
      if (pSub->m_Name_C.length() <= 0)
        pSub->m_Name_C = QString("公司债").toLocal8Bit().data();  // 补数据库缺失
      if (pSub->m_Name_E.length() <= 0) pSub->m_Name_E = "Corporate Bond";
    }
  }
  _add_bondsubtype("DCO");
  {
    CBondType* pSub = type.GetBondSubType("DCO");
    if (pSub != NULL) {
      if (pSub->m_Name_C.length() <= 0)
        pSub->m_Name_C =
            QString("非公开公司债").toLocal8Bit().data();  // 补数据库缺失
      if (pSub->m_Name_E.length() <= 0)
        pSub->m_Name_E = "Private Placement Corporate Bond";
    }
  }
  m_list.push_back(type);
  type.Clear();

  // PPN
  type.m_Code = "PPN";
  type.m_Name_C = "PPN";
  type.m_Name_E = "PPN";

  sub.m_Code = "PPN1";
  sub.m_Name_C = "PPN";
  sub.m_Name_E = "PPN";  // 硬写代码，字典显示“私募债” 暂无法动字典 20160510
  type.AddSubType(sub);

  m_list.push_back(type);
  type.Clear();

  // ABS
  type.m_Code = "ABS";
  type.m_Name_C = "ABS";
  type.m_Name_E = "ABS";
  _add_bondsubtype("AMP");
  _add_bondsubtype("LBS");
  _add_bondsubtype("CBS");
  _add_bondsubtype("MBS");
  m_list.push_back(type);
  type.Clear();

  // 金融机构债
  type.m_Code = "FIB";
  type.m_Name_C = QString("金融机构债").toLocal8Bit().data();
  type.m_Name_E = "Financial Institution Bond";
  _add_bondsubtype("PSB");
  _add_bondsubtype("TET");  // 二级资本工具
  _add_bondsubtype("CBB");
  _add_bondsubtype("CSB");
  _add_bondsubtype("CXB");
  _add_bondsubtype("NCB");
  _add_bondsubtype("SFB");
  _add_bondsubtype("SEB");
  _add_bondsubtype("SSB");
  _add_bondsubtype("SES");
  _add_bondsubtype("HJB");
  _add_bondsubtype("TLC");
  m_list.push_back(type);
  type.Clear();

  // 集合债
  type.m_Code = "CCB";
  type.m_Name_C = QString("集合债").toLocal8Bit().data();
  type.m_Name_E = "Collective";
  _add_bondsubtype("CCB");
  _add_bondsubtype("COB");
  m_list.push_back(type);
  type.Clear();

  // 可转债
  type.m_Code = "CONV";
  type.m_Name_C = QString("可转债").toLocal8Bit().data();
  type.m_Name_E = "Convertible Bond";
  _add_bondsubtype("SCV");
  _add_bondsubtype("CVB");
  m_list.push_back(type);
  type.Clear();

  // NCD
  type.m_Code = "NCD";
  type.m_Name_C = "NCD";
  type.m_Name_E = "NCD";
  _add_bondsubtype("MCD");
  _add_bondsubtype("SPD");
  _add_bondsubtype("SHD");
  _add_bondsubtype("CCD");
  _add_bondsubtype("RRD");
  _add_bondsubtype("RTD");
  _add_bondsubtype("FRD");
  _add_bondsubtype("OTD");
  m_list.push_back(type);
  type.Clear();

  // CRM
  type.m_Code = "CRM";
  type.m_Name_C = "CRM";
  type.m_Name_E = "CRM";
  _add_bondsubtype("CRM");
  _add_bondsubtype("CLN");
  m_list.push_back(type);
  type.Clear();

  // 其他
  type.m_Code = "OTHER";
  type.m_Name_C = QString("其他").toLocal8Bit().data();
  type.m_Name_E = "Others";
  _add_bondsubtype("RAB");
  _add_bondsubtype("INT");
  _add_bondsubtype("PDB");
  m_list.push_back(type);
  type.Clear();
}

CBondTypeList::~CBondTypeList() { m_list.clear(); }

int CBondTypeList::GetSize() { return m_list.size(); }

std::vector<CBondType>* CBondTypeList::GetBondTypeList() { return &m_list; }

CBondType* CBondTypeList::GetBondSubTypeList(const char* strNameC) {
  std::vector<CBondType>::iterator it;
  for (it = m_list.begin(); it != m_list.end(); it++) {
    if (strcmp(it->m_Name_C.c_str(), strNameC) == 0) {
      return &(*it);
    }
  }
  return NULL;
}

CBondType* CBondTypeList::GetBondSubType(const char* szSubBondCode) {
  if (szSubBondCode == NULL) return NULL;
  CBondType* pSubType = NULL;
  std::vector<CBondType>::iterator it;
  for (it = m_list.begin(); it != m_list.end(); it++) {
    CBondType* pBondType = &(*it);
    if (pBondType == NULL) continue;

    pSubType = pBondType->GetBondSubType(szSubBondCode);
    if (pSubType) break;
  }

  return pSubType;
}

//-------------------------------------------------------------------------------------------
CBondTypeV2::CBondTypeV2() {}

CBondTypeV2::CBondTypeV2(const char* pszEnName, const char* pszCnName) {
  m_umapSubType.clear();

  if (pszCnName) m_Name_C = pszCnName;
  if (pszEnName) m_Name_E = pszEnName;
}

CBondTypeV2::~CBondTypeV2() {}

void CBondTypeV2::Clear() {
  m_Name_C.clear();
  m_Name_E.clear();

  m_umapSubType.clear();
}

unsigned int CBondTypeV2::Size() { return m_umapSubType.size(); }

void CBondTypeV2::Add(CBondType& subType) {
  m_umapSubType.insert({subType.m_Code, subType});
}

void CBondTypeV2::Add(CBondType subType) {
  m_umapSubType.insert({subType.m_Code, subType});
}

const CBondTypeV2::UMAP_SUBTYPE& CBondTypeV2::GetMap() { return m_umapSubType; }

const CBondType& CBondTypeV2::GetSubType(const char* pszSubTypeCode) {
  static const CBondType bst;

  if (!pszSubTypeCode) return bst;

  UMAP_SUBTYPE::iterator itrFind =
      m_umapSubType.find(std::string(pszSubTypeCode));

  return itrFind == m_umapSubType.end() ? bst : itrFind->second;
}

#define BUILD_SUBTYPE(szSubType, emBondTypex)              \
  dict.GetBondDict("Bond_Subtype", szSubType, unit);       \
  type.Add(CBondType(szSubType, unit.selective_content_en, \
                     unit.selective_content));             \
  m_umapCode2Type.insert({szSubType, emBondTypex});

CBondTypeMap::CBondTypeMap() {
  //	CBondType sub;
  CBondTypeV2 type;
  BondDict unit;
  CBondDict& dict = CBondDict::instance();

  type.Clear();
  type.m_Name_C = QString("国债").toLocal8Bit().data();
  type.m_Name_E = "Country";
  BUILD_SUBTYPE("BGB", CBondContainer::newBondCountry);
  BUILD_SUBTYPE("SGB", CBondContainer::newBondCountry);
  BUILD_SUBTYPE("EGB", CBondContainer::newBondCountry);
  m_umapType2Body.insert({CBondContainer::newBondCountry, type});

  type.Clear();
  type.m_Name_C = QString("央票").toLocal8Bit().data();
  type.m_Name_E = "Center";
  BUILD_SUBTYPE("SCB", CBondContainer::newBondCenter);
  m_umapType2Body.insert({CBondContainer::newBondCenter, type});

  type.Clear();
  type.m_Name_C = QString("政金债").toLocal8Bit().data();
  type.m_Name_E = "Finance";
  BUILD_SUBTYPE("PBB", CBondContainer::newBondFinance);
  BUILD_SUBTYPE("PSB", CBondContainer::newBondFinance);
  m_umapType2Body.insert({CBondContainer::newBondFinance, type});

  type.Clear();
  type.m_Name_C = QString("地方债").toLocal8Bit().data();
  type.m_Name_E = "Local";
  BUILD_SUBTYPE("LLB", CBondContainer::newBondLocal);
  BUILD_SUBTYPE("TLB", CBondContainer::newBondLocal);
  m_umapType2Body.insert({CBondContainer::newBondLocal, type});

  type.Clear();
  type.m_Name_C = QString("短融").toLocal8Bit().data();
  type.m_Name_E = "Short";
  BUILD_SUBTYPE("CCP", CBondContainer::newBondShort);
  BUILD_SUBTYPE("SSB", CBondContainer::newBondShort);
  BUILD_SUBTYPE("CSP", CBondContainer::newBondShort);
  BUILD_SUBTYPE("LCP", CBondContainer::newBondShort);
  BUILD_SUBTYPE("LSP", CBondContainer::newBondShort);
  m_umapType2Body.insert({CBondContainer::newBondShort, type});

  type.Clear();
  type.m_Name_C = QString("中票").toLocal8Bit().data();
  type.m_Name_E = "China";
  BUILD_SUBTYPE("CMN", CBondContainer::newBondMTN);
  BUILD_SUBTYPE("LMN", CBondContainer::newBondMTN);
  m_umapType2Body.insert({CBondContainer::newBondMTN, type});

  type.Clear();
  type.m_Name_C = QString("企业债").toLocal8Bit().data();
  type.m_Name_E = "Enterpr";
  BUILD_SUBTYPE("CCB", CBondContainer::newBondEnterpr);
  BUILD_SUBTYPE("COB", CBondContainer::newBondEnterpr);
  BUILD_SUBTYPE("RAB", CBondContainer::newBondEnterpr);
  BUILD_SUBTYPE("CEBENT", CBondContainer::newBondEnterpr);
  BUILD_SUBTYPE("LEBENT", CBondContainer::newBondEnterpr);
  m_umapType2Body.insert({CBondContainer::newBondEnterpr, type});

  type.Clear();
  type.m_Name_C = QString("公司债").toLocal8Bit().data();
  type.m_Name_E = "Cop";
  BUILD_SUBTYPE("CEBCOP", CBondContainer::newBondCOP);
  BUILD_SUBTYPE("LEBCOP", CBondContainer::newBondCOP);
  BUILD_SUBTYPE("PPNCOP", CBondContainer::newBondCOP);
  m_umapType2Body.insert({CBondContainer::newBondCOP, type});

  type.Clear();
  type.m_Name_C = "PPN";  // PPN + NULL;
  type.m_Name_E = "PPN";
  type.Add(CBondType("PPNNULL", "PPN", "PPN"));
  m_umapCode2Type.insert({"PPNNULL", CBondContainer::newBondPPN});
  m_umapType2Body.insert({CBondContainer::newBondPPN, type});

  type.Clear();
  type.m_Name_C = "NCD";
  type.m_Name_E = "NCD";
  BUILD_SUBTYPE("MCD", CBondContainer::newBondNCD);
  BUILD_SUBTYPE("SPD", CBondContainer::newBondNCD);
  BUILD_SUBTYPE("SHD", CBondContainer::newBondNCD);
  BUILD_SUBTYPE("CCD", CBondContainer::newBondNCD);
  BUILD_SUBTYPE("RRD", CBondContainer::newBondNCD);
  BUILD_SUBTYPE("RTD", CBondContainer::newBondNCD);
  BUILD_SUBTYPE("FRD", CBondContainer::newBondNCD);
  BUILD_SUBTYPE("OTD", CBondContainer::newBondNCD);
  m_umapType2Body.insert({CBondContainer::newBondNCD, type});

  type.Clear();
  type.m_Name_C = "ABS";
  type.m_Name_E = "Asset Backed";
  BUILD_SUBTYPE("AMP", CBondContainer::newBondABS);
  BUILD_SUBTYPE("LBS", CBondContainer::newBondABS);
  BUILD_SUBTYPE("CBS", CBondContainer::newBondABS);
  BUILD_SUBTYPE("MBS", CBondContainer::newBondABS);
  m_umapType2Body.insert({CBondContainer::newBondABS, type});

  type.Clear();
  type.m_Name_C = "CRM";
  type.m_Name_E = "CRM";
  BUILD_SUBTYPE("CRM", CBondContainer::newBondCRM);
  BUILD_SUBTYPE("CLN", CBondContainer::newBondCRM);
  m_umapType2Body.insert({CBondContainer::newBondCRM, type});
}

UINT CBondTypeMap::GetTypeEm(const char* pszSubType,
                             const char* pszEntCor /* =NULL */) {
  if (!pszSubType || strlen(pszSubType) == 0)
    return CBondContainer::newBondOther;

  UMAP_CODE2TYPE::iterator itrFind =
      m_umapCode2Type.find(std::string(pszSubType));
  if (itrFind != m_umapCode2Type.end()) return itrFind->second;

  std::string sKey = pszSubType;
  if (!pszEntCor || strlen(pszEntCor) == 0) {
    sKey += "NULL";
  } else if (!pszEntCor || strlen(pszEntCor) > 0) {
    sKey += pszEntCor;
  }

  if (sKey.compare(pszSubType) != 0) {
    UMAP_CODE2TYPE::iterator itrFindx = m_umapCode2Type.find(std::string(sKey));
    if (itrFindx != m_umapCode2Type.end()) return itrFindx->second;
  }

  return CBondContainer::newBondOther;
}

CBondTypeMap::~CBondTypeMap() {}

CBondTypeMap CBondTypeMap::instance() {
  static CBondTypeMap s_btm;
  return s_btm;
}

UINT CBondTypeMap::Size() { return m_umapType2Body.size(); }

const CBondTypeMap::UMAP_TYPE2BODY& CBondTypeMap::GetMap() {
  return m_umapType2Body;
}

const CBondTypeV2& CBondTypeMap::GetType(UINT nCode) {
  static const CBondTypeV2 btv2("Other", QString("其它").toLocal8Bit().data());

  UMAP_TYPE2BODY::iterator itrFind = m_umapType2Body.find(nCode);

  return itrFind == m_umapType2Body.end() ? btv2 : itrFind->second;
}

const CBondTypeV2& CBondTypeMap::GetType(const char* pszSubType,
                                         const char* pszEntCor /* = NULL */) {
  return GetType(GetTypeEm(pszSubType, pszEntCor));
}